#include "glwidget.h"
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QTimerEvent>
#include <QPainter>
#include <QOpenGLFramebufferObject>
#include <QDebug>

GlWidget::GlWidget(QWidget *parent)
    : QOpenGLWidget(parent)
    , shaderProgram(nullptr)
    , texture(nullptr)
    , textureId(0)
{
    // 初始化顶点数据
    // 位置坐标 (x, y, z) 和纹理坐标 (s, t)
    GLfloat vertices[] = {
        -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,  // 左下角
        1.0f, -1.0f, 0.0f, 1.0f, 1.0f,   // 右下角
        -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,   // 左上角
        1.0f, 1.0f, 0.0f, 1.0f, 0.0f     // 右上角
    };
    
    memcpy(this->vertices, vertices, sizeof(this->vertices));
}

GlWidget::~GlWidget()
{
    makeCurrent();
    delete texture;
    delete shaderProgram;
    doneCurrent();
}

void GlWidget::setImage(const QImage &image)
{
    if (image.isNull())
        return;
        
    currentImage = image;
    
    if (isValid()) {
        makeCurrent();
        updateTextureData();
        doneCurrent();
        update();
    }
}

QImage GlWidget::getImage() const
{
    return currentImage;
}

void GlWidget::initializeGL()
{
    initializeOpenGLFunctions();
    
    // 初始化着色器
    initShaders();
    
    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    
    // 启用混合
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    // 创建纹理
    texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
}

void GlWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void GlWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    if (!shaderProgram || !texture)
        return;
        
    shaderProgram->bind();
    texture->bind();
    
    // 设置顶点属性
    glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
    glVertexAttribPointer(texCoordAttr, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices + 3);
    
    glEnableVertexAttribArray(posAttr);
    glEnableVertexAttribArray(texCoordAttr);
    
    // 绘制
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    glDisableVertexAttribArray(posAttr);
    glDisableVertexAttribArray(texCoordAttr);
    
    shaderProgram->release();
}

void GlWidget::updateTexture()
{
    if (!currentImage.isNull()) {
        makeCurrent();
        updateTextureData();
        doneCurrent();
        update();
    }
}

void GlWidget::updateTextureData()
{
    if (currentImage.isNull())
        return;
        
    if (!texture->isCreated()) {
        texture->setSize(currentImage.width(), currentImage.height());
        texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
        texture->allocateStorage();
    }
    
    // 更新纹理数据
    texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, currentImage.bits());
}

void GlWidget::initShaders()
{
    if (!shaderProgram) {
        shaderProgram = new QOpenGLShaderProgram(this);
    }
    
    // 顶点着色器源码
    const char *vertexShaderSource =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "layout (location = 1) in vec2 aTexCoord;\n"
        "out vec2 TexCoord;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = vec4(aPos, 1.0);\n"
        "   TexCoord = aTexCoord;\n"
        "}\n";
        
    // 片段着色器源码
    const char *fragmentShaderSource =
        "#version 330 core\n"
        "in vec2 TexCoord;\n"
        "out vec4 FragColor;\n"
        "uniform sampler2D ourTexture;\n"
        "void main()\n"
        "{\n"
        "   FragColor = texture(ourTexture, TexCoord);\n"
        "}\n";
        
    shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    shaderProgram->link();
    
    // 获取属性位置
    posAttr = shaderProgram->attributeLocation("aPos");
    texCoordAttr = shaderProgram->attributeLocation("aTexCoord");
    matrixUniform = shaderProgram->uniformLocation("matrix");
}